項目15 型演算とジェネリック型を使って重複を避ける
型の重複
型の重複を防ぐ方法
型に名前をつけて再利用する
extendsを使った型拡張によって、必要最低限の型を定義する
マップ型を使う
構造は同じだが詳細な型が異なる場合は、ジェネリック型を使う
ただ、やり過ぎはNG
プロパティと型を共通化する場合は、それらが本当に共通のものかを確認する
重複は間違った抽象化より遥かに無害である
下記の共通化は悪い例
code:ts
// これをしないでください!
interface NamedAndIdentified {id: number; name: string;} // この型に明確な意味がない
interface Product extends NamedAndIdentified {
priceDollars: number;
}
interface Customer extends NamedAndIdentified {
address: string;
}
マップ型
mapped typeとも言う
具体例
汎用的な型であるStateと局所的な状態を表すTopNapStateという型を作る場合
下記の例は、重複するフィールドと型があるため、保守性が悪い
code:ts
interface State {
userId: string;
pageTitle: string;
recentFiles: string[];
pageContents: string;
}
interface TopNavState {
userId: string;
pageTitle: string;
recentFiles: string[];
}
マップ型を使って、State型を用いて型を生成するようにする
code:ts
type TopNavState = {
};
Pickでも同様のことが可能
code:ts
type TopNavState = Pick<State, 'userId' | 'pageTitle' | 'recentFiles'>;
特定の型を各プロパティをオプションにした新たな型を作る場合
マップ型とkeyofを使うことで可能
code:ts
interface Options {width: number; height: number; color: string; label: string;}
Partialでも同様のことが可能
code:ts
type OptionsUpdate = Partial<Options>
型定義のキーと値のマッピングを破天させたい場合
as節を使うことで対応できる
code:ts
interface ShortToLong {q: 'search'; n: 'numberOfResults';}
type LongToShort = { [k in keyof ShortToLong as ShortToLongk]: k }; // ^? type LongToShort = { search: "q"; numberOfResults: "n"; }
ホモモーフィック
マップ型のインデックス節で、K in keyof Tが使われているか、それと同等の形式の場合、ホモモーフィックなマップ型として扱う
これは、修飾子(readonlyなど)やTSDocが新しい型に引き継がれることを意味する
https://scrapbox.io/files/6813254ed2cfebe9de9a21cd.png
code:ts
interface Customer {
/** 顧客の希望する呼び名 */
title?: string;
/** システムに登録された正式な名前 */
readonly name: string;
}
type PickTitle = Pick<Customer, 'title'>;
type PickName = Pick<Customer, 'name'>;
Pickはジェネリック型の一例
タグ付きユニオンで重複排除
下記の型のtypeフィールドの型だけを抽出する
code:ts
interface SaveAction {type: 'save'; // ...}
interface LoadAction {type: 'load'; // ...}
type Action = SaveAction | LoadAction;
type ActionType = 'save' | 'load'; // 型が重複する
Acrionユニオンにインデックスアクセスすれば重複を排除できる
code:ts
type ActionType = Action'type'; // ^? type ActionType = "save" | "load"
typeofを使って型生成する
値の形状と一致する型を定義
code:ts
const INIT_OPTIONS = {
width: 640,
height: 480,
color: '#00FF00',
label: 'VGA',
};
type Options = typeof INIT_OPTIONS;
関数やメソッドの戻り値として推論される型に、名前をつけて型を定義
code:ts
function getUserInfo(userId: string) {
// ...
return {
userId,
name,
age,
height,
weight,
favoriteColor,
};
}
type UserInfo = ReturnType<typeof getUserInfo>;